//   Copyright 2012,2013 Vaughn Vernon
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
package com.saasovation.identityaccess.domain.model;

import com.saasovation.common.annotation.TestContainers;
import com.saasovation.common.domain.model.DomainEventPublisher;
import com.saasovation.identityaccess.IdentityAccessAppTest;
import com.saasovation.common.TestBase;
import com.saasovation.identityaccess.domain.model.identity.*;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.jupiter.api.BeforeEach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

@SpringBootTest(classes = IdentityAccessAppTest.class)
@TestContainers(use = true)
@Transactional
public abstract class DomainTestBase extends TestBase {
    protected static final String FIXTURE_PASSWORD = "SecretPassword!";
    protected static final String FIXTURE_TENANT_DESCRIPTION = "This is a test tenant.";
    protected static final String FIXTURE_TENANT_NAME = "Test Tenant";
    protected static final String FIXTURE_USER_EMAIL_ADDRESS = "jdoe@saasovation.com";
    protected static final String FIXTURE_USER_EMAIL_ADDRESS2 = "zdoe@saasovation.com";
    protected static final String FIXTURE_USERNAME = "jdoe";
    protected static final String FIXTURE_USERNAME2 = "zdoe";
    protected static final long TWENTY_FOUR_HOURS = (1000L * 60L * 60L * 24L);


    @DynamicPropertySource
    public static void dataSourceProperties(DynamicPropertyRegistry registry) {
        if (!useTestContainers(DomainTestBase.class)) {
            return;
        }
        initMySqlContainer(registry);
    }

    @Autowired
    protected SessionFactory sessionFactory;
    private Tenant tenant;

    public DomainTestBase() {
        super();
    }

    @BeforeEach
    public void beforeEach() {
        DomainEventPublisher.instance().reset();
    }

    protected Session getCurrentSession() {
        return this.sessionFactory.getCurrentSession();
    }

    protected ContactInformation contactInformation() {
        return new ContactInformation(new EmailAddress(FIXTURE_USER_EMAIL_ADDRESS),
                new PostalAddress("123 Pearl Street",
                        "Boulder",
                        "CO",
                        "80301",
                        "US"),
                new Telephone("303-555-1210"),
                new Telephone("303-555-1212"));
    }

    protected Date dayAfterTomorrow() {
        return new Date(this.today().getTime() + (TWENTY_FOUR_HOURS * 2));
    }

    protected Date dayBeforeYesterday() {
        return new Date(this.today().getTime() - (TWENTY_FOUR_HOURS * 2));
    }

    protected Person personEntity(Tenant aTenant) {
        return new Person(aTenant.tenantId(),
                new FullName("John", "Doe"),
                this.contactInformation());
    }

    protected Person personEntity2(Tenant aTenant) {
        return new Person(aTenant.tenantId(),
                new FullName("Zoe", "Doe"),
                new ContactInformation(new EmailAddress(FIXTURE_USER_EMAIL_ADDRESS2),
                        new PostalAddress(
                                "123 Pearl Street",
                                "Boulder",
                                "CO",
                                "80301",
                                "US"),
                        new Telephone("303-555-1210"),
                        new Telephone("303-555-1212")));
    }

    protected RegistrationInvitation registrationInvitationEntity(Tenant aTenant) {
        Date today = new Date();
        Date tomorrow = new Date(today.getTime() + TWENTY_FOUR_HOURS);
        return aTenant.offerRegistrationInvitation("Today-and-Tomorrow: " + System.nanoTime())
                .startingOn(today)
                .until(tomorrow);
    }

    protected Tenant tenantAggregate() {
        if (this.tenant == null) {
            TenantId tenantId = DomainRegistry.tenantRepository().nextIdentity();
            this.tenant = new Tenant(tenantId,
                    FIXTURE_TENANT_NAME,
                    FIXTURE_TENANT_DESCRIPTION,
                    true);
            DomainRegistry.tenantRepository().add(tenant);
        }
        return this.tenant;
    }

    protected Date yesterday() {
        return new Date(this.today().getTime() - TWENTY_FOUR_HOURS);
    }

    protected Date today() {
        return new Date();
    }

    protected Date tomorrow() {
        return new Date(this.today().getTime() + TWENTY_FOUR_HOURS);
    }

    protected User userAggregate() {
        Tenant tenant = this.tenantAggregate();
        RegistrationInvitation registrationInvitation = this.registrationInvitationEntity(tenant);
        return tenant.registerUser(registrationInvitation.invitationId(),
                FIXTURE_USERNAME,
                FIXTURE_PASSWORD,
                new Enablement(true, null, null),
                this.personEntity(tenant));
    }

    protected User userAggregate2() {
        Tenant tenant = this.tenantAggregate();
        RegistrationInvitation registrationInvitation = this.registrationInvitationEntity(tenant);
        return tenant.registerUser(registrationInvitation.invitationId(),
                FIXTURE_USERNAME2,
                FIXTURE_PASSWORD,
                new Enablement(true, null, null),
                this.personEntity2(tenant));
    }
}
